/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "resize_load_nat.h"

#include <locale.h>
#include <stdbool.h>
#include <time.h>

#include "node.h"
#include "device_manager.h"
#include "hmfs_common.h"

namespace OHOS {
namespace Hmfs {
ResizeLoadNat::ResizeLoadNat(ResizeLoad *loadPtr) : load_(loadPtr)
{
	config_ = load_->GetConfig();
	sbInfo_ = load_->GetSbInfo();
}

int32_t ResizeLoadNat::InitNidBitmapBegin()
{
    struct NodeAddressTable *nat = sbInfo_->naTable;
    int nidBitmapSize = (nat->maxNid + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
    struct CurSegmentInfo *curseg = (struct CurSegmentInfo *) (sbInfo_->smInfoTable->curSegmentArray + CURSEG_HOT_DATA);
    struct SummaryBlockData *sum = curseg->segSumBlk;
    struct JournalEntry *journal = &sum->journal;

    nat->nidBitmap = static_cast<char *>(calloc(nidBitmapSize, 1));
    if (!nat->nidBitmap) {
        return -ENOMEM;
    }
    /* arbitrarily set 0 bit */
    HmfsCommon::GetInstance().HmfsSetBit(0, nat->nidBitmap);
    
    uint16_t nNats = LE16_TO_NATIVE(journal->nNats);
    if (nNats > NAT_JOURNAL_ENTRIES) {
        HMFS_ERROR("\tError: hmfs_init_nid_bitmap truncate nNats(%u) to NAT_JOURNAL_ENTRIES(%zu)",
            nNats, NAT_JOURNAL_ENTRIES);
        journal->nNats = NATIVE_TO_LE16(NAT_JOURNAL_ENTRIES);
        config_->fixOn = 1;
    }

    for (int32_t i = 0; i < nNats; i++) {
        uint32_t addr = LE32_TO_NATIVE(journal->natJ.entries[i].ne.blockId);
        if (!IsValidBlkAddr(sbInfo_, addr)) {
            HMFS_ERROR("\tError: hmfs_init_nid_bitmap: addr(%u) is invalid!!!", addr);
            journal->nNats = NATIVE_TO_LE16(i);
            config_->fixOn = 1;
            continue;
        }

        uint32_t nid = LE32_TO_NATIVE(journal->natJ.entries[i].nid);
        if (!IsValidNid(sbInfo_, nid)) {
            HMFS_ERROR("\tError: hmfs_init_nid_bitmap: nid(%u) is invalid!!!", nid);
            journal->nNats = NATIVE_TO_LE16(i);
            config_->fixOn = 1;
            continue;
        }
        if (addr != NULL_ADDR)
            HmfsCommon::GetInstance().HmfsSetBit(nid, nat->nidBitmap);
    }
    return SUCCESS_CODE;
}

int32_t ResizeLoadNat::InitNodeManager()
{
    struct SuperBlockData *sbData = sbInfo_->rawSuper;
    struct CheckPointData *cpData = sbInfo_->ckptData;
    struct NodeAddressTable *nat = sbInfo_->naTable;

    nat->natBlkaddr = GetLeValue(sbData->natBlkId);

    /* segment_count_nat includes pair segment so divide to 2. */
    unsigned int natSegs = GetLeValue(sbData->segmentCountInNAT) >> 1;
    nat->natBlocks = natSegs << GetLeValue(sbData->logBlksPerSeg);
    nat->maxNid = NAT_ENTRY_PER_BLOCK * nat->natBlocks;
    nat->fcnt = 0;
    nat->natCnt = 0;
    nat->initScanNid = GetLeValue(cpData->nextFreeNodeId);
    nat->nextScanNid = GetLeValue(cpData->nextFreeNodeId);

    nat->bitmapSize = GetBitmapSize(sbInfo_, NAT_BITMAP);

    nat->natBitmap = static_cast<char *>(malloc(nat->bitmapSize));
    if (!nat->natBitmap) {
        return -ENOMEM;
    }
    unsigned char *versionBitmap = (unsigned char *)load_->GetBitmapPtr(NAT_BITMAP);
    if (!versionBitmap) {
        return -EFAULT;
    }
    /* copy version bitmap */
    memcpy(nat->natBitmap, versionBitmap, nat->bitmapSize);
    return InitNidBitmapBegin();
}

int32_t ResizeLoadNat::BuildNodeManager()
{
    HMFS_DEBUG("Enter BuildNodeManager");
    sbInfo_->naTable = static_cast<struct NodeAddressTable *>(malloc(sizeof(struct NodeAddressTable)));
    if (!sbInfo_->naTable) {
        return -ENOMEM;
    }
    int err = InitNodeManager();
    if (err != SUCCESS_CODE) {
        return err;
    }
    return SUCCESS_CODE;
}

int32_t ResizeLoadNat::HmfsLateInitNidBitmap()
{
    HMFS_DEBUG("Enter HmfsLateInitNidBitmap");
    struct NodeAddressTable *nat = NM_I(sbInfo_);
    uint32_t startBlk;
    if (!(config_->func == SLOAD || config_->func == FSCK)) {
        return 0;
    }
    struct natBlockData *natBlock = static_cast<struct natBlockData *>(malloc(HMFS_BLKSIZE));
    if (!natBlock) {
        free(nat->nidBitmap);
        return -ENOMEM;
    }

    load_->HmfsRaMetaPages(0, NAT_BLOCK_OFFSET(nat->maxNid), META_NAT);
    for (uint32_t nid = 0; nid < nat->maxNid; nid++) {
        if (!(nid % NAT_ENTRY_PER_BLOCK)) {
            int ret;
            startBlk = CurrentNatAddr(sbInfo_, nid, nullptr);
            ret = HmfsIo::GetInstance().DevReadBlock(natBlock, startBlk);
            ASSERT(ret >= 0);
        }

        if (natBlock->entries[nid % NAT_ENTRY_PER_BLOCK].blockId)
            HmfsCommon::GetInstance().HmfsSetBit(nid, nat->nidBitmap);
    }
    free(natBlock);
    return 0;
}

} // namespace Hmfs
} // namespace OHOS
